home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / tex / lametex_.z / lametex_ / lametex / src / Font.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-19  |  11.5 KB  |  496 lines

  1. /* Font.C
  2.  *
  3.  * Anything having to do with changing the style, family, or size of the
  4.  * fonts is handled through this Font class.
  5.  *
  6.  * Copyright 1992 Jonathan Monsarrat. Permission given to freely distribute,
  7.  * edit and use as long as this copyright statement remains intact.
  8.  *
  9.  */
  10.  
  11. #include "Global.h"
  12. #include "Font.h"
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <stdlib.h>
  16.  
  17. FontUsed *Font::_fonts_used[MAXFONTS];
  18. int Font::_num_fonts_used;
  19.  
  20. // Build a list of fonts actually used, along with the characters
  21. // used for each font.
  22. FontUsed::FontUsed(char *style, char *petname, int font)
  23. {
  24.    strcpy(_style, style);
  25.    strcpy(_petname, petname);
  26.    _font = font;
  27.    for(int x=0; x<256; x++)
  28.       _charused[x] = (x >= '0' && x <= '9') ? 1 : 0;
  29. }
  30.  
  31. void FontUsed::used(char *textstr)
  32. {
  33.    for(int x=0; textstr[x]; x++)
  34.       _charused[textstr[x]] = 1;
  35. }
  36.  
  37. int FontUsed::font()
  38. {
  39.    return _font;
  40. }
  41.  
  42. void FontUsed::dump(ofstream &outfile)
  43. {
  44.    outfile << "{" << _style << endl;
  45.  
  46.    int num=0;
  47.    for(int x=0; x < 256; x++)
  48.       if(_charused[x]) {
  49.          if(num++ > 25) {
  50.         outfile << endl << endl;
  51.         num=0;
  52.      }
  53.      switch(x) {
  54.          case '^':   // Can't handle these. Sorry!
  55.      case '{':
  56.      case '}':
  57.         break;
  58.      case '&':
  59.      case '#':
  60.      case '_':
  61.      case '%':
  62.      case '$':
  63.         outfile << '\\';
  64.      default:
  65.         outfile << (char) x << " ";
  66.         break;
  67.      }
  68.       }
  69.  
  70.    outfile << "`` '' ." << endl;
  71.    outfile << "}" << endl;
  72. }
  73.  
  74. int FontUsed::match(char *textstr)
  75. {
  76.    return !strcmp(textstr,_petname);
  77. }
  78.  
  79. char *FontUsed::petname()
  80. {
  81.    return _petname;
  82. }
  83.  
  84. Font::Font()
  85. {
  86.    _basesize = 10;
  87.    _fontsize = 10;
  88.    strcpy(_fontstyle,"rm");
  89.    strcpy(_fontsizecmd,"\\normalsize");
  90.    _fonts_used[0] = new FontUsed("\\normalsize\\rm", "/cm10rm", 1);
  91.    _num_fonts_used = 1;
  92.    Global::files->outfile << endl;
  93.    _currentused = 0;
  94.    _pending = 1;
  95.    _pending_whitespace = 1;
  96. }
  97.  
  98. Font::Font(Font *base)
  99. {
  100.    _basesize = base->_basesize;
  101.    _fontsize = base->_fontsize;
  102.    strcpy(_fontstyle, base->_fontstyle);
  103.    strcpy(_fontsizecmd, base->_fontsizecmd);
  104.    _currentused = base->_currentused;
  105.    _pending = base->_pending;
  106.    _pending_whitespace = base->_pending_whitespace;
  107. }
  108.  
  109. Font::~Font()
  110. {
  111.    for(int x=0; x < _num_fonts_used; x++)
  112.       delete _fonts_used[x];
  113. }
  114.  
  115. Param *Font::copy()
  116. {
  117.    return new Font(this);
  118. }
  119.  
  120.  
  121. void Font::newsize(float val)
  122. {
  123.    if(_fontsize != val) {
  124.       _fontsize = (int) val;
  125.  
  126.       /* We are updating the size of the font, so we had better update
  127.        * also the amount of space to skip between lines. This is done
  128.        * by doing a set statement on \baselinestretch.
  129.        */
  130.       if(!Global::files->plain_text_output) {
  131.        Stack::set(Environment::PLength, 0,
  132.               Stack::get(Environment::PLength, Length::Parameter,
  133.                  "\\baselinestretch"), "\\baselinestretch");
  134.       }
  135.       _pending = 1;    // Print the postscript command for this.
  136.       _pending_whitespace = Global::files->whitespace_next();
  137.    }
  138. }
  139.  
  140. void Font::set_fontstyle(char *style)
  141. {
  142.    if(strcmp(_fontstyle,style)!=0) {
  143.       strcpy(_fontstyle,style);
  144.       _pending = 1;    // Print the postscript command for this.
  145.       _pending_whitespace = Global::files->whitespace_next();
  146.    }
  147. }
  148.  
  149. int Font::set(int subtype, float value, char *textstr)
  150. {
  151.    /* The Font Family is hard-coded to "cm" for Computer Modern */
  152.    switch(subtype) {
  153.       /* Base sizes */
  154.    case Base10pt:    // Do nothing; this is the default.
  155.       break;
  156.    case Base11pt:
  157.       delete _fonts_used[0];
  158.       _fonts_used[0] = new FontUsed("\\normalsize\\rm", "/cm11rm", 1);
  159.       Global::files->outfile << endl;
  160.       Global::files->outfile << "/basefont /cm11rm def" << endl;
  161.       _basesize = 11;
  162.       _fontsize = 11;
  163.       _pending = 1;
  164.       _pending_whitespace = Global::files->whitespace_next();
  165.       break;
  166.    case Base12pt:
  167.       delete _fonts_used[0];
  168.       _fonts_used[0] = new FontUsed("\\normalsize\\rm", "/cm12rm", 1);
  169.       Global::files->outfile << endl;
  170.       Global::files->outfile << "/basefont /cm12rm def" << endl;
  171.       _basesize = 12;
  172.       _fontsize = 12;
  173.       _pending = 1;
  174.       _pending_whitespace = Global::files->whitespace_next();
  175.       break;
  176.  
  177.       /* _Font styles */
  178.    case Italic:
  179.       if(strcmp(_fontstyle,"it")==0)
  180.      strcpy(_fontstyle,"rm");        // Double Italic is Roman!
  181.       else
  182.      strcpy(_fontstyle,"it");
  183.       _pending = 1;    // Print the postscript command for this.
  184.       _pending_whitespace = Global::files->whitespace_next();
  185.       break;
  186.    case Bold:
  187.       set_fontstyle("bf");
  188.       break;
  189.    case Roman:
  190.       set_fontstyle("rm");
  191.       break;
  192.    case SansSerif:
  193.       set_fontstyle("sf");
  194.       break;
  195.    case Slant:
  196.       set_fontstyle("sl");
  197.       break;
  198.    case SmallCaps:
  199.       set_fontstyle("sc");
  200.       break;
  201.    case Typewriter:
  202.       set_fontstyle("tt");
  203.       break;
  204.  
  205.       /* Sizes relative to the base size */
  206.    case Tiny:
  207.       strcpy(_fontsizecmd,"\\tiny");
  208.       switch(_basesize) {
  209.       case 10:
  210.       default:
  211.          newsize(4);
  212.          break;
  213.       case 11:
  214.       case 12:
  215.          newsize(6);
  216.          break;
  217.       }
  218.       break;
  219.    case Scriptsize:
  220.       strcpy(_fontsizecmd,"\\scriptsize");
  221.       switch(_basesize) {
  222.       case 10:
  223.       default:
  224.          newsize(6);
  225.          break;
  226.       case 11:
  227.       case 12:
  228.          newsize(7);
  229.          break;
  230.       }
  231.       break;
  232.    case Footnotesize:
  233.       strcpy(_fontsizecmd,"\\footnotesize");
  234.       switch(_basesize) {
  235.       case 10:
  236.       default:
  237.          newsize(7);
  238.          break;
  239.       case 11:
  240.          newsize(8);
  241.          break;
  242.       case 12:
  243.          newsize(10);
  244.          break;
  245.       }
  246.       break;
  247.    case Small:
  248.       strcpy(_fontsizecmd,"\\small");
  249.       switch(_basesize) {
  250.       case 10:
  251.       default:
  252.      newsize(8);
  253.      break;
  254.       case 11:
  255.      newsize(10);
  256.      break;
  257.       case 12:
  258.      newsize(11);
  259.      break;
  260.       }
  261.       break;
  262.    case Normalsize:
  263.       strcpy(_fontsizecmd,"\\normalsize");
  264.       newsize(_basesize);
  265.       break;
  266.    case large:
  267.       strcpy(_fontsizecmd,"\\large");
  268.       switch(_basesize) {
  269.       case 10:
  270.       default:
  271.      newsize(11);
  272.      break;
  273.       case 11:
  274.      newsize(12);
  275.      break;
  276.       case 12:
  277.      newsize(13);
  278.      break;
  279.       }
  280.       break;
  281.    case Large:
  282.       strcpy(_fontsizecmd,"\\Large");
  283.       switch(_basesize) {
  284.       case 10: 
  285.       case 11:
  286.       default:
  287.      newsize(13);
  288.      break;
  289.       case 12:
  290.      newsize(15);
  291.      break;
  292.       }
  293.       break;
  294.    case LARGE:
  295.       strcpy(_fontsizecmd,"\\LARGE");
  296.       switch(_basesize) {
  297.       case 10: 
  298.       case 11:
  299.       default:
  300.      newsize(15);
  301.      break;
  302.       case 12:
  303.      newsize(18);
  304.      break;
  305.       }
  306.       break;
  307.    case huge:
  308.       strcpy(_fontsizecmd,"\\huge");
  309.       switch(_basesize) {
  310.       case 10:
  311.       case 11:
  312.       default:
  313.      newsize(18);
  314.      break;
  315.       case 12:
  316.      newsize(22);
  317.      break;
  318.       }
  319.       break;
  320.    case Huge:
  321.       strcpy(_fontsizecmd,"\\Huge");
  322.       newsize(22);
  323.       break;
  324.    case Currentused:
  325.       _currentused = do_command(textstr, textstr,
  326.                 Global::files->whitespace_next(), 0);
  327.       break;
  328.    case Pending:
  329.       if(_pending) {
  330.      postscript_set(0);
  331.      _pending = 0;
  332.       }
  333.       break;
  334.    case Size:
  335.       set_fontstyle("");
  336.       newsize(value);
  337.       break;
  338.       /* These font styles aren't handled right now */
  339.    case Used:
  340.       _fonts_used[_currentused]->used(textstr);
  341.       break; 
  342.    case FunnyPrint:
  343.       Global::files->outfile << endl << "[ 0";
  344.       if(Global::files->whitespace_next())
  345.      Global::files->outfile << " false";
  346.       else
  347.      Global::files->outfile << " true";
  348.       Global::files->outfile << " ] NewFont " << textstr << " NW " << endl;
  349.       _pending = 1;    // Print the postscript command for this.
  350.       _pending_whitespace = Global::files->whitespace_next();
  351. //      postscript_set(0);
  352.       break;
  353.    default:
  354.       break;
  355.    }
  356.    return TRUE;
  357. }
  358.  
  359. float Font::get(int subtype, char *comparestr)
  360.    switch(subtype) {
  361.    case Base:
  362.       return(_basesize);
  363.    case Currentused:
  364.       return(_currentused);
  365.    case Pending:
  366.       return(_pending);
  367.    case Style:
  368.       return(!strcmp(comparestr,_fontstyle));
  369.    case ShutDown:
  370.       if(!Global::files->plain_text_output)
  371.          shutdown();
  372.       break;
  373.    case Size:
  374.    default:
  375.       break;
  376.    }
  377.    return(_fontsize);
  378. }
  379.  
  380. void Font::revert(Param *from)
  381. {
  382.    int size = (int)from->get(Size,"");
  383.  
  384.    if(size != _fontsize || !from->get(Style,_fontstyle)
  385.       || from->get(Pending,"") || _currentused != from->get(Currentused,""))
  386.       _pending = 1;    // Print the postscript command for this.
  387.       _pending_whitespace = Global::files->whitespace_next();
  388. }
  389.  
  390. void Font::use_command(char *style, char *petname, int font)
  391. {
  392.    _fonts_used[_num_fonts_used++] = new FontUsed(style,petname, font);
  393. }
  394.  
  395. int Font::do_command(char *style, char *petname, int whitespace, int font)
  396. {
  397.    for(int used=0; used < _num_fonts_used; used++)
  398.       if(_fonts_used[used]->match(petname))
  399.      break;
  400.    if(_num_fonts_used >= MAXFONTS)
  401.       Global::files->fatal_error("Too many fonts");
  402.    if(used >= _num_fonts_used)
  403.       use_command(style, petname, font);
  404.  
  405.    Global::files->outfile << endl << "[ " << used+1;
  406.  
  407.    if(whitespace)
  408.       Global::files->outfile << " false";
  409.    else
  410.       Global::files->outfile << " true";
  411.  
  412.    Global::files->outfile << " ] NewFont    % " << petname << endl;
  413.    return(used);
  414. }
  415.  
  416. void Font::postscript_set(int)
  417. {
  418.    /* The Font Family is hard-coded to "cm" for Computer Modern */
  419.    char petname[MAXSTRING];
  420.  
  421.    sprintf(petname,"/cm%d%s",_fontsize,_fontstyle);
  422.    char style[MAXSTRING];
  423.    sprintf(style,"%s\\%s",_fontsizecmd,_fontstyle);
  424.    _currentused = do_command(style, petname, _pending_whitespace, 1);
  425. }
  426.  
  427. // This is an important routine which builds a dummy latex files
  428. // Just to trick LaTeX into giving us the proper fonts.
  429. void Font::shutdown()
  430. {
  431.    cerr << "Making dummy file for snarfing LaTeX fonts..." << endl;
  432.    ofstream dummy("lametex.tex");
  433.    if(_basesize == 10)
  434.     dummy << "\\documentstyle{report}" << endl;
  435.    else
  436.     dummy << "\\documentstyle[" << _basesize << "pt]{report}" << endl;
  437.    dummy << "\\pagestyle{empty}" << endl;
  438.    dummy << "\\begin{document}" << endl;
  439.    for(int x=0; x < _num_fonts_used; x++)
  440.       _fonts_used[x]->dump(dummy);
  441.    dummy << "\\end{document}" << endl;
  442.    dummy.close();
  443.    cerr << "Snarfing LaTeX fonts..." << endl;
  444.    system( LATEX );  
  445.    system( DVIPS ); 
  446.  
  447.    ifstream latex_postscript("lametex.ps");
  448.    if(!latex_postscript) {           // Open file failed?
  449.       cerr << "Unable to open postscript temp file lametex.ps for reading"
  450.        << endl;
  451.       exit (-1);
  452.    }
  453.  
  454.    ofstream lametex_postscript("lametex.PS");
  455.    if(!lametex_postscript) {           // Open file failed?
  456.       cerr << "Unable to open postscript temp file lametex.PS for writing"
  457.        << endl;
  458.       exit (-1);
  459.    }
  460.  
  461.    char line[MAXSTRING];
  462.    while(!latex_postscript.eof()) {
  463.       latex_postscript.getline(line, MAXSTRING, '\n');
  464.       if(strstr(line,"TeXDict begin")==line)
  465.      break;
  466.    }
  467.  
  468.    lametex_postscript << line << endl;
  469.    while(!latex_postscript.eof()) {
  470.       latex_postscript.getline(line, MAXSTRING, '\n');
  471.       lametex_postscript << line << endl;
  472.       if(strstr(line,"%%EndSetup"))
  473.      break;
  474.    }
  475.  
  476.    int y;
  477.    for(x=_num_fonts_used-1, y=0; x >= 0 ; x--)
  478.       if(_fonts_used[x]->font())
  479.      lametex_postscript << _fonts_used[x]->petname()
  480.                 << "{ pop F" << (char) ('a' + y++)
  481.                 << " } bind def" << endl;
  482.  
  483.    lametex_postscript << "/fontnames [" << endl;
  484.    lametex_postscript << "/TIMESROMAN" << endl;
  485.  
  486.    for(x=0; x < _num_fonts_used; x++)
  487.       lametex_postscript << _fonts_used[x]->petname() << endl;
  488.    lametex_postscript << "] def" << endl;
  489.       
  490.    latex_postscript.close();
  491.    lametex_postscript.close();
  492.    system("rm lametex.tex lametex.dvi lametex.ps");
  493.    cerr << "  ** SNARF! **" << endl;
  494. }
  495.